package org.xw.service.impl;

import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.teaopenapi.models.Config;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.xw.dto.AddPersonDto;
import org.xw.dto.FriendDto;
import org.xw.dto.UserDto;
import org.xw.mapper.GzhMapper;
import org.xw.mapper.ManagerCheckMapper;
import org.xw.mapper.UserMapper;
import org.xw.pojo.FriendPojo;
import org.xw.pojo.GzhPojo;
import org.xw.pojo.ManagerCheckPojo;
import org.xw.pojo.UserPojo;
import org.xw.service.UserService;
import org.xw.utils.JWTUtil;
import org.xw.utils.MD5Util;
import org.xw.utils.RedisTagUtil;

import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

@Service
public class UserServiceImpl implements UserService {

    private static final String USER_TAG = "用户_";
    private static final String JWT_USER_ID = "user_id";
    private static final String JWT_USERNAME_TAG = "username";
    private static final String AUTHORIZATION = "Authorization";

    @Autowired
    UserMapper mapper;//从ioc容器中注入UserMapper对象

    @Autowired
    ManagerCheckMapper checkMapper;//注入EmployeeCheckMapper对象

    @Autowired
    RedisTemplate redisTemplate;

    @Resource
    GzhMapper gzhMapper;

    /**
     * 获取string数据类型使用的redis存储器
     *
     * @return
     */
    private ValueOperations getStringOps() {
        ValueOperations stringOps = redisTemplate.opsForValue();
        return stringOps;
    }

    private HashOperations getHashOps() {
        return redisTemplate.opsForHash();
    }


    /**
     * 解析请求头携带的token，返回target内容
     *
     * @param request
     * @param headerName
     * @param target
     * @return
     */
    private String analyzeToken(HttpServletRequest request, String headerName, String target) {
        String header = request.getHeader(headerName);
        if (header != null) {
            String[] strings = header.split(" ");
            DecodedJWT token = JWTUtil.getToken(strings[1]);
            Map<String, Claim> claims = token.getClaims();
            String s = claims.get(target).asString();
            return s;
        } else return null;
    }


    /**
     * 传入电话号码phone和密码password进行注册，生成初始用户昵称
     *
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean signUser(UserPojo user) {
        Integer userExist = mapper.isUserExist(user.getPhone());
        if (userExist == 0) {
            try {
                String password = user.getPassword();
                String s = MD5Util.md5(password);
                user.setPassword(s);
                Boolean result = mapper.signUser(user);
                if (result) {
                    String username = USER_TAG + user.getId();
                    user.setUsername(username);
                    Boolean isSuccess = mapper.updateUsername(user);
                    if (isSuccess) {
                        return true;
                    } else throw new Exception("注册失败!");
                } else throw new Exception("注册失败！");
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        return false;
    }

    /**
     * 传入电话号码phone和密码password登录，成功返回map集合，map集合内包含用户信息user以及验证user_token
     *
     * @param phone
     * @param password
     * @return
     */
    @Override
    public HashMap<String, Object> login(String phone, String password) {
        UserPojo login = mapper.login(phone, password);
        System.out.println(login);
        if (login != null) {
            String loginPassword = login.getPassword();
            String s = MD5Util.md5(password);
            if (loginPassword.equals(s)) {
                HashMap hashMap = setLoginInfo(login);

                //将UserPojo中的数据放入映射类UserDto中，隐藏敏感信息
                UserDto user = UserDto.toUser(login);
                hashMap.put("user", user);
                return hashMap;
            } else {
                HashMap<String, Object> hashMap = new HashMap<>();
                hashMap.put("error", new UserPojo());
                return hashMap;
            }
        } else
            return null;
    }

    /**
     * 从请求头中获取用户id以此为键进行用户信息查询
     *
     * @param request
     * @return
     */
    @Override
    public HashMap getSelfInfo(HttpServletRequest request) {
        String authorization = request.getHeader("Authorization");
        if (authorization != null) {
            String[] s = authorization.split(" ");
            DecodedJWT token = JWTUtil.getToken(s[1]);
            Map<String, Claim> claims = token.getClaims();
            String userIdStringForm = claims.get(JWT_USER_ID).asString();
            Integer userId = Integer.valueOf(userIdStringForm);
            UserDto userInfo = mapper.getUserInfo(userId);

            if (userInfo != null) {
                ValueOperations stringOps = getStringOps();
                stringOps.set(RedisTagUtil.USER_INFO_TAG + userId, userInfo);


                HashMap<Object, Object> hashMap = new HashMap<>();
                hashMap.put("user_info", userInfo);

                //获取用户的公众号信息
                List<GzhPojo> gzhs = gzhMapper.getGzhPojos(userId);
                if (gzhs != null){ hashMap.put("gzhs_info",gzhs);}
                return hashMap;
            } else return null;
        } else return null;
    }

    /**
     * 传入用户id，查询用户的好友信息
     *
     * @param userId
     * @return
     */
    @Override
    public List getFriendInfo(Integer userId) {

        HashOperations hashOps = redisTemplate.opsForHash();
        //获取redis中的好友数据
        List values = hashOps.values(RedisTagUtil.USER_FRIEND_LIST + userId);


        //如果redis中不存在好友数据，则从数据库中查询，并存入redis
        if (values.isEmpty()) {

            List<FriendDto> friendArray = new ArrayList<>();
            List<FriendPojo> friends = mapper.friendInfo(userId, "1");
            if (!friends.isEmpty()) {

                for (FriendPojo friend : friends) {
                    FriendDto friendDto = FriendDto.toFriend(friend);
                    UserDto userInfo = mapper.getUserInfo(friendDto.getFriendId());
                    friendDto.setUserInfo(userInfo);
                    friendArray.add(friendDto);
                    //将查询到的数据存入redis
                    hashOps.put(RedisTagUtil.USER_FRIEND_LIST + userId, String.valueOf(friendDto.getFriendId()), friendDto);
                }

                return friendArray;
            } else return null;

        } else return values;

    }

    /**
     * 传入目标好友的id，自身信息对象user，向目标好友发送好友请求
     *
     * @param addPerson
     * @return
     */
    @Override
    public Boolean sendFriendRequest(AddPersonDto addPerson) {
        LocalDateTime now = LocalDateTime.now();
        addPerson.setAcquaintanceTime(now);
        return mapper.sendFriendRequest(addPerson);
    }

    /**
     * 传入好友请求对象，进行同意，拒绝等操作. 结果码：0，操作失败！；1，同意请求；2.拒绝请求
     *
     * @param friendRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer agreeRequest(FriendDto friendRequest) {
        String authorization = friendRequest.getAuthorization();
        if (authorization.equals("1")) {
            try {
                friendRequest.setAcquaintanceTime(LocalDateTime.now());
                Boolean result = mapper.agreeRequest(friendRequest);
                System.out.println(friendRequest);
                if (result) {
                    FriendDto friend = new FriendDto();
                    friend.setUserId(friendRequest.getFriendId());
                    friend.setFriendId(friendRequest.getUserId());
                    friend.setAuthorization("1");
                    friend.setAcquaintanceTime(LocalDateTime.now());
                    Boolean consequence = mapper.addFriend(friend);
                    if (consequence) {
                        redisTemplate.delete(RedisTagUtil.USER_FRIEND_REQUESTS + friendRequest.getUserId());
                        redisTemplate.delete(RedisTagUtil.USER_FRIEND_LIST + friendRequest.getUserId());
                        return 1;
                    } else {
                        throw new Exception("无法反向增加好友");
                    }
                } else {
                    throw new Exception("无法同意");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return 0;
            }
        } else {
            Boolean result = mapper.agreeRequest(friendRequest);
            if (result) {
                return 2;
            } else return 0;
        }
    }


    /**
     * 只传入用户id，查询数据库中所有好友请求
     *
     * @param userId
     * @return
     */
    @Override
    public List friendRequests(Integer userId) {

        HashOperations hashOps = redisTemplate.opsForHash();
        List friend_requests = (List) hashOps.get(RedisTagUtil.USER_FRIEND_REQUESTS + userId, "friend_requests");
        if (friend_requests != null) {
            return friend_requests;
        } else {
            List list = new ArrayList<>();
            List<FriendPojo> friends = mapper.friendInfo(userId, "");
            if (friends != null) {
                for (FriendPojo friend : friends) {
                    FriendDto friendDto = FriendDto.toFriend(friend);
                    UserDto userInfo = mapper.getUserInfo(friend.getFriendId());
                    friendDto.setUserInfo(userInfo);
                    list.add(friendDto);
                }
                hashOps.put(RedisTagUtil.USER_FRIEND_REQUESTS + userId, "friend_request", list);
                return list;
            } else return null;
        }


    }

    /**
     * 传入想要删除的好友对象，将其authorization修改为3，并将数据中的userId以及friendId进行互换，修改对应数据的authorization为3
     *
     * @param targetFriend
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteFriend(FriendDto targetFriend) {
        FriendDto reverseFriend = new FriendDto();
        reverseFriend.setUserId(targetFriend.getFriendId());
        reverseFriend.setFriendId(targetFriend.getUserId());
        try {
            Boolean result = mapper.deleteFriend(targetFriend);
            if (result) {
                Boolean isSuccess = mapper.reverseDelete(reverseFriend);
                if (isSuccess) {
                    redisTemplate.delete(RedisTagUtil.USER_FRIEND_LIST + targetFriend.getUserId());
                    return true;
                } else {
                    throw new Exception("反转删除失败!");
                }
            } else {
                throw new Exception("删除好友失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 传入一段文本，将这段文本放入user表以及gzh表进行模糊搜索
     *
     * @param content
     * @return
     */
    @Override
    public HashMap searchInfo(String content, HttpServletRequest request) {
        String userIdStringForm = analyzeToken(request, "Authorization", JWT_USER_ID);
        if (userIdStringForm != null) {
            HashOperations hashOps = getHashOps();
            HashMap hashMap = (HashMap) hashOps.get(RedisTagUtil.USER_SEARCH_KEY + userIdStringForm, content);

            if (hashMap != null) {
                return hashMap;
            } else {
                HashMap<Object, Object> map = new HashMap<>();
                List<UserDto> users = mapper.searchUser(content);
                map.put("users", users);
                hashOps.put(RedisTagUtil.USER_SEARCH_KEY + userIdStringForm, content, map);
                return map;
            }
        } else return null;

    }

    /**
     * 用户传入新昵称，进行昵称修改
     *
     * @param newName
     * @param request
     * @return
     */
    @Override
    public Integer updateUsername(String newName, HttpServletRequest request) {
        //返回结果0：请求头未获取到内容；1：修改成功；2：修改失败
        String userIdStringForm = analyzeToken(request, "Authorization", JWT_USER_ID);
        if (userIdStringForm != null) {
            Integer userId = Integer.valueOf(userIdStringForm);
            UserPojo user = new UserPojo();
            user.setUsername(newName);
            user.setId(userId);
            Boolean result = mapper.updateUsername(user);
            if (result) {
                ValueOperations stringOps = getStringOps();
                UserDto userInfo = mapper.getUserInfo(userId);
                stringOps.set(RedisTagUtil.USER_INFO_TAG + userInfo.getId(), userInfo);
                return 1;
            } else return 2;
        } else return 0;
    }

    /**
     * 传入新头像文件，通过解析token获取用户id，进行对应修改
     *
     * @param headImage
     * @param request
     * @return
     */
    @Override
    public Integer updateHeadImage(MultipartFile headImage, HttpServletRequest request) {
        String userIdStringForm = analyzeToken(request, "Authorization", JWT_USER_ID);
        if (userIdStringForm != null) {
            //文件保存路径
            File filePath = new File("G:\\image_project\\xw\\" + userIdStringForm + "\\headImage");
            if (!filePath.exists()) {
                boolean mkdir = filePath.mkdirs();
            }

            // 生成随机文件名
            String filename = UUID.randomUUID().toString() + "." + FilenameUtils.getExtension(headImage.getOriginalFilename());
            File newFile = new File(filePath, filename);
            // 保存文件到本地磁盘
            try {
                headImage.transferTo(newFile);
                String databasePath = "http://93ex15636hn2.vicp.fun/image/" + userIdStringForm + "/headImage/" + filename;
                UserPojo user = new UserPojo();
                user.setId(Integer.valueOf(userIdStringForm));
                user.setHeadImage(databasePath);
                Boolean result = mapper.updateHeadImage(user);

                if (result) {
                    return 1;//修改头像审核申请提交成功
                } else return 2;//文件可能上传成功，但是提交申请失败
            } catch (IOException e) {
                e.printStackTrace();
                return 3;//文件上传失败
            }
        } else
            return 0;//未获取到用户id，可能用户未登录
    }

    /**
     * 用户传入新地址address，后台从请求头中解析token获取用户id
     *
     * @param request
     * @param userInfo
     * @return
     */
    @Override
    public Boolean updateAddress(HttpServletRequest request, UserPojo userInfo) {
        String userIdStringForm = analyzeToken(request, "Authorization", JWT_USER_ID);
        if (userIdStringForm != null) {
            userInfo.setId(Integer.valueOf(userIdStringForm));
            Boolean result = mapper.updateAddress(userInfo);
            if (result) {
                redisTemplate.delete(RedisTagUtil.USER_INFO_TAG + userIdStringForm);
                return true;
            }
        }
        return false;
    }

    /**
     * 传入好友数据主键id，用户userId，好友friendId，备注remark
     *
     * @param friend
     * @param request
     * @return
     */
    @Override
    public Boolean setFriendRemark(FriendDto friend, HttpServletRequest request) {
        String userIdStringForm = analyzeToken(request, "Authorization", JWT_USER_ID);
        if (userIdStringForm != null) {
            friend.setUserId(Integer.valueOf(userIdStringForm));
            Boolean result = mapper.setFriendRemark(friend);
            if (result) {
                redisTemplate.delete(RedisTagUtil.USER_FRIEND_LIST + userIdStringForm);
                return true;
            } else return false;
        }
        return false;
    }

    /**
     * 传入用户id，查询其信息
     *
     * @param id
     * @return
     */
    @Override
    public FriendDto friendInfo(Integer id, HttpServletRequest request) {
        String userIdStringForm = analyzeToken(request, AUTHORIZATION, JWT_USER_ID);
        if (userIdStringForm != null) {
            FriendDto friendInfo = mapper.getFriendInfo(Integer.valueOf(userIdStringForm), id);
            if (friendInfo != null) {
                UserDto userInfo = mapper.getUserInfo(id);
                friendInfo.setUserInfo(userInfo);
                return friendInfo;
            } else return null;
        } else
            return null;
    }

    /**
     * 发送请求解封请求    用户发现自己被封禁后提交解封请求
     *
     * @param request 获取请求头
     * @return 是否成功
     */
    @Override
    public Boolean addUnsealRequest(HttpServletRequest request) {
        String userIdStringForm = analyzeToken(request, AUTHORIZATION, JWT_USER_ID);
        if (userIdStringForm != null) {
            ManagerCheckPojo managerCheck = new ManagerCheckPojo();
            managerCheck.setUserId(Integer.valueOf(userIdStringForm));
            managerCheck.setCheckType(2);
            managerCheck.setCheckContent("请求解封账号。");
            Boolean result = mapper.addUnsealRequest(managerCheck);
            if (result) {
                return true;
            } else return false;
        } else
            return false;
    }

    /**
     * 登出   传入请求，清除redis中对应数据实现登出
     *
     * @param request 请求
     * @return 是否登出成功
     */
    @Override
    public Boolean logout(HttpServletRequest request) {
        String userIdStringForm = JWTUtil.analyzeToken(request, AUTHORIZATION, JWT_USER_ID);
        if (userIdStringForm != null) {
            Boolean delete = redisTemplate.delete(RedisTagUtil.USER_LOGIN_TOKEN + userIdStringForm);
            redisTemplate.delete(RedisTagUtil.USER_SEARCH_KEY + userIdStringForm);
            redisTemplate.delete(RedisTagUtil.USER_FRIEND_LIST + userIdStringForm);
            redisTemplate.delete(RedisTagUtil.USER_INFO_TAG + userIdStringForm);
            redisTemplate.delete(RedisTagUtil.USER_FRIEND_REQUESTS + userIdStringForm);
            return delete;
        } else
            return null;
    }

    /**
     * 短信登录验证
     *
     * @param phone
     * @return
     */
    @Override
    public Boolean loginByPhone(String phone) {
        if (phone != null) {

            Config config = new Config();
            config.setAccessKeyId("LTAI5tATtM9kHGUCRaPeYpTd");
            config.setAccessKeySecret("KnInrM0j9aa6wJVA2VVH6Ppb3rMDvx");
            int code = ThreadLocalRandom.current().nextInt(100000, 1000000);

            try {
                Client client = new Client(config);
                SendSmsRequest request = new SendSmsRequest();
                request.setSignName("阿里云短信测试");
                request.setPhoneNumbers(phone);
                request.setTemplateCode("SMS_154950909");
                request.setTemplateParam("{'code':'" + code + "'}");


                SendSmsResponse response = client.sendSms(request);
                System.out.println(response.getBody().message);
                System.out.println(response.getBody().code);
                System.out.println(response.getBody().bizId.toString());
                System.out.println(response.getStatusCode());

                if (response.getBody().getCode().equals("OK")) {
                    ValueOperations stringOps = getStringOps();
                    stringOps.set(RedisTagUtil.USER_LOGIN_CODE + phone, code);
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        } else return false;

    }

    /**
     * 传入电话号码与验证码，进行校验登录
     *
     * @param phone 电话号码
     * @param code  验证码
     * @return 校验是否成功
     */
    @Override
    public HashMap loginByPhone(String phone, Integer code) {
        if (phone != null) {
            ValueOperations stringOps = getStringOps();
            Integer rCode = (Integer) stringOps.get(RedisTagUtil.USER_LOGIN_CODE + phone);
            if (rCode != null && rCode.equals(code)) {
                UserPojo login = mapper.login(phone, "");
                if (login != null) {
                    return setLoginInfo(login);
                } else {
                    HashMap<Object, Object> hashMap = new HashMap<>();
                    hashMap.put("error", "该账户还未注册，请前往注册");
                    return hashMap;
                }
            } else {
                HashMap<Object, Object> hashMap = new HashMap<>();
                hashMap.put("error", "验证码错误");
                return hashMap;
            }
        } else return null;
    }

    /**
     * 将mapper查询的数据传入， 获取其中id以及username，存入hashmap以及redis
     *
     * @param userInfo 数据库中的用户数据
     * @return 保存数据的hashmap
     */
    private HashMap setLoginInfo(UserPojo userInfo) {
        HashMap<Object, Object> hashMap = new HashMap<>();

        HashMap<String, String> map = new HashMap<>();
        map.put(JWT_USER_ID, String.valueOf(userInfo.getId()));
        map.put(JWT_USERNAME_TAG, userInfo.getUsername());
        String token = JWTUtil.getToken(map);

        ValueOperations stringOps = getStringOps();
        stringOps.set(RedisTagUtil.USER_LOGIN_TOKEN + userInfo.getId(), token);
        hashMap.put("user_token", token);
        return hashMap;
    }
}
